<!--
 * @Description: 画布
 * @Autor: HuiSir<273250950@qq.com>
 * @Date: 2021-11-29 14:25:31
 * @LastEditTime: 2021-12-02 15:39:29
-->
<template>
    <div ref="contentBox" class="right-top content-box">
        <super-flow ref="superFlow" :node-list="nodeList" :link-list="linkList" :origin="origin"
            :node-menu="nodeMenuList" :link-addable="false" :link-base-style="{color:'#999'}"
            @drop.native.prevent="drop" @dragover.native.prevent>
            <template v-slot:node="{meta}">
                <div :class="`flow-node node-${meta.nodeId}`" @mousedown="bindSelect($event,meta)">
                    <header class="header-icon">
                        <img :draggable="false" v-if="meta.type===1" src="../imgs/in.svg">
                        <img :draggable="false" v-if="meta.type===2" src="../imgs/out.svg">
                        <img :draggable="false" v-if="meta.type===3" src="../imgs/clean.svg">
                    </header>
                    <section>
                        {{ meta.name }}
                    </section>
                </div>
            </template>
        </super-flow>
    </div>
</template>

<script>
import SuperFlow from 'vue-super-flow'
import 'vue-super-flow/lib/index.css'
import { canvasMove, rawList2Tree } from './helper'

const nodeSize = [100, 60] //节点尺寸
export default {
    name: 'myCanvas',
    components: {
        SuperFlow,
    },
    data() {
        return {
            nodeList: [], // 初始化节点列表
            linkList: [], // 初始化连线列表
            origin: [0, 0], // 坐标原点
        }
    },
    computed: {
        // 节点菜单
        nodeMenuList() {
            const _this = this
            return [
                // 右键菜单配置
                [
                    {
                        label: '清洗',
                        disable: false,
                        hidden: (node) => node.meta.type === 2,
                        selected(node) {
                            const { graph, position, id, meta } = node

                            // 这里要避免位置重叠，查询当前节点所有子节点Y位置
                            const currNodeLinkEndY = graph.linkList
                                .filter((item) => item.start.id == id)
                                .map((item) => item.end.coordinate[1])

                            // 计算当前子节点Y坐标
                            const currCoordinateY = currNodeLinkEndY.length
                                ? Math.max(...currNodeLinkEndY) + 60 + nodeSize[1]
                                : position[1]

                            const nodeId = Date.now()
                            const newNode = {
                                id: nodeId,
                                pid: id,
                                width: nodeSize[0],
                                height: nodeSize[1],
                                coordinate: [position[0] + 100 + nodeSize[0], currCoordinateY],
                                meta: {
                                    nodeId,
                                    nodePid: id,
                                    type: 3,
                                    name: '清洗',
                                    data: meta.data,
                                },
                            }
                            // 新增节点
                            const endNode = _this.addNode(newNode, graph)
                            // 连线
                            graph.addLink({
                                id: Date.now(),
                                start: node,
                                end: endNode,
                                startAt: [100, 40],
                                endAt: [0, 40],
                                meta: null,
                            })
                        },
                    },
                    {
                        label: '输出',
                        disable: false,
                        hidden: (node) => node.meta.type === 2,
                        selected(node) {
                            const { graph, position, id, meta } = node

                            // 这里要避免位置重叠，查询当前节点所有子节点Y位置
                            const currNodeLinkEndY = graph.linkList
                                .filter((item) => item.start.id == id)
                                .map((item) => item.end.coordinate[1])

                            // 计算当前子节点Y坐标
                            const currCoordinateY = currNodeLinkEndY.length
                                ? Math.max(...currNodeLinkEndY) + 60 + nodeSize[1]
                                : position[1]

                            const nodeId = Date.now()
                            const newNode = {
                                id: nodeId,
                                pid: id,
                                width: nodeSize[0],
                                height: nodeSize[1],
                                coordinate: [position[0] + 100 + nodeSize[0], currCoordinateY],
                                meta: {
                                    nodeId,
                                    nodePid: id,
                                    type: 2,
                                    name: '输出',
                                    data: meta.data,
                                },
                            }
                            // 添加新节点
                            const endNode = _this.addNode(newNode, graph)
                            // 添加连线
                            graph.addLink({
                                id: Date.now(),
                                start: node,
                                end: endNode,
                                startAt: [100, 40],
                                endAt: [0, 40],
                                meta: null,
                            })
                        },
                    },
                ],
                [
                    {
                        label: '删除节点',
                        disable: false,
                        selected(node) {
                            node.remove()
                        },
                    },
                ],
            ]
        },
        // 所有节点
        allNode() {
            return this.$refs.superFlow.graph.nodeList
        },
        // 节点树
        nodeTree() {
            const nodeTree = rawList2Tree(
                JSON.parse(JSON.stringify(this.allNode)),
                'pid',
                'children'
            )
            this.$emit('allNode', this.allNode)
            this.$emit('allLink', this.$refs.superFlow.graph.linkList)
            this.$emit('nodeTree', nodeTree)
            return nodeTree
        },
    },
    methods: {
        // 添加新节点
        addNode(node, graph) {
            if (graph) {
                return graph.addNode(node)
            } else {
                this.$refs.superFlow.graph.addNode(node)
            }
        },
        // 拖入
        drop(e) {
            const _data = JSON.parse(e.dataTransfer.getData('data'))
            console.log('拖放结束', _data)
            const { offsetX, offsetY } = e
            // 创建节点
            const nodeId = Date.now()
            this.addNode({
                id: nodeId,
                width: nodeSize[0],
                height: nodeSize[1],
                coordinate: [offsetX - nodeSize[0] / 2, offsetY - nodeSize[1] / 2],
                meta: {
                    nodeId,
                    type: 1, // 1-输入；2-输出；3-清洗
                    name: _data.name,
                    data: _data,
                },
            })
        },
        // 节点选定
        bindSelect({ button }, meta) {
            if (button != 0) return
            // 高亮
            document.querySelectorAll('.flow-node').forEach((nodeEl) => {
                nodeEl.classList.remove('selected')
                if (nodeEl.classList.contains(`node-${meta.nodeId}`)) {
                    nodeEl.classList.add('selected')
                }
            })
            this.$emit('handlerNodeSelect', meta)
        },
    },
    mounted() {
        // 畫布拖拽
        canvasMove(this.$refs.superFlow.$el, this.$refs.contentBox)
    },
}
</script>
<style lang="scss" scoped>
.content-box {
    position: relative;
    width: 100%;
    height: 100%;
    background: #f2f2f5;
    overflow: hidden;
    .super-flow {
        position: absolute;
        left: calc(50% - 2000px);
        top: calc(50% - 2000px);
        width: 4000px;
        height: 4000px;
        cursor: grab;
        background: antiquewhite;
        .flow-node {
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            &.selected {
                border: 1px solid #1296db;
            }
        }
    }
}
</style>
<style lang="scss">
.super-flow__menu-container .super-flow__menu-item-content {
    text-align: left;
}
.super-flow__node {
    background: transparent;
    box-shadow: none;
    border: 0;
    &:hover {
        box-shadow: none;
        border: 1px solid #1296db;
    }
}
.flow-node {
    .header-icon {
        img {
            width: 32px;
            height: 32px;
        }
    }
    section {
        font-size: 16px;
        text-align: center;
    }
}
</style>
